var gapi_loaded = false;
// Import R2 sync functionality
importScripts('r2_sync.js');

var gapi_inited = false;

//TODO check chrome.runtime.lastError for all storage.local operations

function do_load_dictionary(file_text) {
    var lines = file_text.split('\n');
    var rare_words = {};
    var rank = 0;
    var prev_lemma = null;
    for (var i = 0; i < lines.length; ++i) {
        var fields = lines[i].split('\t');
        if (i + 1 === lines.length && fields.length == 1)
            break;
        var form = fields[0];
        var lemma = fields[1];
        var cocaRank = Number(fields[2]);
        var oxfordRank = Number(fields[3]);
        if (lemma !== prev_lemma) {
            rank += 1;
            prev_lemma = lemma;
        }
        rare_words[fields[0]] = [fields[1], cocaRank, oxfordRank];
    }
    local_storage = chrome.storage.local;
    local_storage.set({"words_discoverer_eng_dict": rare_words});
    local_storage.set({"wd_word_max_rank": rank});
}


function load_eng_dictionary() {
    var file_path = chrome.runtime.getURL("eng_dict.txt");
    fetch(file_path)
        .then(response => response.text())
        .then(text => do_load_dictionary(text))
        .catch(error => console.error('Error loading dictionary:', error));
}


function do_load_idioms(file_text) {
    var lines = file_text.split('\n');
    var rare_words = {};
    for (var lno = 0; lno < lines.length; ++lno) {
        var fields = lines[lno].split('\t');
        if (lno + 1 === lines.length && fields.length == 1)
            break;
        var words = fields[0].split(' ');
        for (var i = 0; i + 1 < words.length; ++i) {
            key = words.slice(0, i + 1).join(' ');
            rare_words[key] = -1;
        }
        key = fields[0];
        rare_words[key] = fields[1];
    }
    local_storage = chrome.storage.local;
    local_storage.set({"wd_idioms": rare_words});
}


function load_idioms() {
    file_path = chrome.runtime.getURL("eng_idioms.txt");
    fetch(file_path)
        .then(response => response.text())
        .then(text => do_load_idioms(text))
        .catch(error => console.error('Error loading idioms:', error));
}

function load_skip_words() {
    file_path = chrome.runtime.getURL("eng_skip.txt");
    fetch(file_path)
        .then(response => response.text())
        .then(text => {
            var new_words = parse_vocabulary(text);
            add_new_words(new_words, false);
        })
        .catch(error => console.error('Error loading skip words:', error));
}


function report_sync_failure(error_msg) {
    chrome.storage.local.set({"wd_last_sync_error": error_msg}, function () {
        chrome.runtime.sendMessage({'sync_feedback': 1});
    });
}


function load_script(url, callback_func) {
    // Manifest V3 service workers cannot load external scripts due to CSP restrictions
    // Google Drive sync is not available in this version
    console.warn('External script loading not supported in Manifest V3 service workers:', url);
    report_sync_failure('Google Drive sync is not available in Manifest V3. External script loading is blocked by Content Security Policy.');
}


function authorize_user(interactive_authorization) {
    chrome.identity.getAuthToken({interactive: interactive_authorization}, function (token) {
        if (token === undefined) {
            report_sync_failure('Unable to get oauth token');
        } else {
            gapi.client.setToken({access_token: token});
            sync_user_vocabularies();
        }
    });
}


function transform_key(src_key) {
    var dc = window.atob(src_key);
    dc = dc.substring(3);
    dc = dc.substring(0, dc.length - 6);
    return dc;
}


function generate_key() {
    var protokey = 'b2ZCQUl6YVN5Q2hqM2xvZkJPWnV2TUt2TGNCSlVaa0RDTUhZa25NWktBa25NWktB';
    return transform_key(protokey);
}


function list_to_set(src_list) {
    result = {};
    for (var i = 0; i < src_list.length; ++i) {
        result[src_list[i]] = 1;
    }
    return result;
}


function substract_from_set(lhs_set, rhs_set) {
    for (var key in rhs_set) {
        if (rhs_set.hasOwnProperty(key) && lhs_set.hasOwnProperty(key)) {
            delete lhs_set[key];
        }
    }
}


function add_to_set(lhs_set, rhs_set) {
    for (var key in rhs_set) {
        if (rhs_set.hasOwnProperty(key)) {
            lhs_set[key] = 1;
        }
    }
}


function serialize_vocabulary(entries) {
    keys = [];
    for (var key in entries) {
        if (entries.hasOwnProperty(key)) {
            keys.push(key);
        }
    }
    keys.sort();
    return keys.join('\r\n');
}


function parse_vocabulary(text) {
    // code duplication with parse_vocabulary in import.js
    var lines = text.split('\n');
    var found = [];
    for (var i = 0; i < lines.length; ++i) {
        var word = lines[i];
        if (i + 1 === lines.length && word.length <= 1)
            break;
        if (word.slice(-1) === '\r') {
            word = word.slice(0, -1);
        }
        found.push(word);
    }
    return found;
}


function create_new_dir(dir_name, success_cb) {
    var body = {"name": dir_name, "mimeType": "application/vnd.google-apps.folder", "appProperties": {"wdfile": '1'}};
    var req_params = {'path': 'https://www.googleapis.com/drive/v3/files/', 'method': 'POST', 'body': body};
    gapi.client.request(req_params).then(function (jsonResp, rawResp) {
        if (jsonResp.status == 200) {
            success_cb(jsonResp.result.id);
        } else {
            report_sync_failure('Bad dir create status: ' + jsonResp.status);
        }
    });
}


function create_new_file(fname, parent_dir_id, success_cb) {
    var body = {"name": fname, "parents": [parent_dir_id], "appProperties": {"wdfile": '1'}, "mimeType": "text/plain"};
    var req_params = {'path': 'https://www.googleapis.com/drive/v3/files', 'method': 'POST', 'body': body};
    gapi.client.request(req_params).then(function (jsonResp, rawResp) {
        if (jsonResp.status == 200) {
            success_cb(jsonResp.result.id);
        } else {
            report_sync_failure('Bad file create status: ' + jsonResp.status);
        }
    });
}


function upload_file_content(file_id, file_content, success_cb) {
    var req_params = {
        'path': 'https://www.googleapis.com/upload/drive/v3/files/' + file_id,
        'method': 'PATCH',
        'body': file_content
    };
    gapi.client.request(req_params).then(function (jsonResp, rawResp) {
        if (jsonResp.status == 200) {
            success_cb();
        } else {
            report_sync_failure('Bad upload content status: ' + jsonResp.status);
        }
    });
}


function fetch_file_content(file_id, success_cb) {
    // https://developers.google.com/drive/v3/web/manage-downloads
    var full_query_url = 'https://www.googleapis.com/drive/v3/files/' + file_id + '?alt=media';
    gapi.client.request({'path': full_query_url, 'method': 'GET'}).then(function (jsonResp, rawResp) {
        if (jsonResp.status != 200) {
            report_sync_failure('Bad status: ' + jsonResp.status + ' for getting content of file: ' + file_id);
            return;
        }
        var file_content = jsonResp.body;
        success_cb(file_id, file_content);
    });
}


function find_gdrive_id(query, found_cb, not_found_cb) {
    // generic function to find single object id
    var full_query_url = 'https://www.googleapis.com/drive/v3/files?q=' + encodeURIComponent(query);
    gapi.client.request({'path': full_query_url, 'method': 'GET'}).then(function (jsonResp, rawResp) {
        if (jsonResp.status != 200) {
            report_sync_failure('Bad status: ' + jsonResp.status + ' for query: ' + query);
            return;
        }
        if (jsonResp.result.files.length > 1) {
            report_sync_failure('More than one object found for query: ' + query);
            return;
        } else if (jsonResp.result.files.length == 1) {
            var drive_id = jsonResp.result.files[0].id
            found_cb(drive_id);
            return;
        }
        not_found_cb();
    });
}


function apply_cloud_vocab(entries) {
    var sync_date = new Date();
    var sync_time = sync_date.getTime();
    var new_state = {
        "wd_last_sync_error": null,
        "wd_user_vocabulary": entries,
        "wd_user_vocab_added": {},
        "wd_user_vocab_deleted": {},
        "wd_last_sync": sync_time
    };
    chrome.storage.local.set(new_state, function () {
        chrome.runtime.sendMessage({'sync_feedback': 1});
    });
}


function sync_vocabulary(dir_id, vocab) {
    merge_and_upload_vocab = function (file_id, file_content) {
        vocab_list = parse_vocabulary(file_content);
        var entries = list_to_set(vocab_list);
        substract_from_set(entries, vocab.deleted);
        add_to_set(entries, vocab.added);
        merged_content = serialize_vocabulary(entries);

        set_merged_vocab = function () {
            apply_cloud_vocab(entries);
        }
        upload_file_content(file_id, merged_content, set_merged_vocab);
    }

    merge_vocab_to_cloud = function (file_id) {
        fetch_file_content(file_id, merge_and_upload_vocab);
    }

    var vocab_file_name = vocab.name + ".txt";
    var file_query = "name = '" + vocab_file_name + "' and trashed = false and appProperties has { key='wdfile' and value='1' } and '" + dir_id + "' in parents";
    create_new_file_wrap = function () {
        create_new_file(vocab_file_name, dir_id, merge_vocab_to_cloud);
        var new_added = {};
        add_to_set(new_added, vocab.all);
        add_to_set(new_added, vocab.added);
        vocab.added = new_added;
    }
    find_gdrive_id(file_query, merge_vocab_to_cloud, create_new_file_wrap);
}


function backup_vocabulary(dir_id, vocab, success_cb) {
    merge_and_upload_backup = function (file_id, file_content) {
        vocab_list = parse_vocabulary(file_content);
        var entries = list_to_set(vocab_list);
        add_to_set(entries, vocab.all);
        add_to_set(entries, vocab.deleted);
        add_to_set(entries, vocab.added);
        merged_content = serialize_vocabulary(entries);
        upload_file_content(file_id, merged_content, success_cb);
    }
    merge_backup_to_cloud = function (file_id) {
        fetch_file_content(file_id, merge_and_upload_backup);
    }

    var backup_file_name = "." + vocab.name + ".backup";
    var backup_query = "name = '" + backup_file_name + "' and trashed = false and appProperties has { key='wdfile' and value='1' } and '" + dir_id + "' in parents";
    create_new_backup_file_wrap = function () {
        create_new_file(backup_file_name, dir_id, merge_backup_to_cloud);
    }
    find_gdrive_id(backup_query, merge_backup_to_cloud, create_new_backup_file_wrap);
}


function perform_full_sync(vocab) {
    var dir_name = "Words Discoverer Sync";
    var dir_query = "name = '" + dir_name + "' and trashed = false and appProperties has { key='wdfile' and value='1' }";
    backup_and_sync_vocabulary = function (dir_id) {
        sync_vocabulary_wrap = function () {
            sync_vocabulary(dir_id, vocab);
        }
        backup_vocabulary(dir_id, vocab, sync_vocabulary_wrap);
    }
    create_new_dir_wrap = function () {
        create_new_dir(dir_name, backup_and_sync_vocabulary);
    }
    find_gdrive_id(dir_query, backup_and_sync_vocabulary, create_new_dir_wrap);
}


function sync_user_vocabularies() {
    chrome.storage.local.get(['wd_user_vocabulary', 'wd_user_vocab_added', 'wd_user_vocab_deleted'], function (result) {
        var wd_user_vocabulary = result.wd_user_vocabulary;
        var wd_user_vocab_added = result.wd_user_vocab_added;
        var wd_user_vocab_deleted = result.wd_user_vocab_deleted;
        if (typeof wd_user_vocabulary === 'undefined') {
            wd_user_vocabulary = {};
        }
        if (typeof wd_user_vocab_added === 'undefined') {
            wd_user_vocab_added = Object.assign({}, wd_user_vocabulary);
        }
        if (typeof wd_user_vocab_deleted === 'undefined') {
            wd_user_vocab_deleted = {};
        }
        var vocab = {
            "name": "my_vocabulary",
            "all": wd_user_vocabulary,
            "added": wd_user_vocab_added,
            "deleted": wd_user_vocab_deleted
        };
        perform_full_sync(vocab);
    });
}


function init_gapi(interactive_authorization) {
    gapikey = generate_key();
    init_params = {apiKey: gapikey};
    gapi.client.init(init_params).then(function () {
        gapi_inited = true;
        authorize_user(interactive_authorization);
    }, function (reject_reason) {
        var error_msg = 'Unable to init client. Reject reason: ' + reject_reason;
        console.error(error_msg);
        report_sync_failure(error_msg);
    });
}


function load_and_init_gapi(interactive_authorization) {
    load_script('https://apis.google.com/js/api.js', function () {
        gapi.load('client', function () {
            gapi_loaded = true;
            init_gapi(interactive_authorization);
        });
    });
}


function start_sync_sequence(interactive_authorization) {
    // Use R2 sync instead of Google Drive
    start_r2_sync_sequence(interactive_authorization);
}


function add_new_words(new_words, syncIfNeeded) {
    chrome.storage.local.get(['wd_user_vocabulary', 'wd_user_vocab_added', 'wd_user_vocab_deleted'], function(result) {
        var user_vocabulary = result.wd_user_vocabulary;
        var wd_user_vocab_added = result.wd_user_vocab_added;
        var wd_user_vocab_deleted = result.wd_user_vocab_deleted;
        var num_added = 0;
        var new_state = {"wd_user_vocabulary": user_vocabulary};
        for (var i = 0; i < new_words.length; ++i) {
            var word = new_words[i];
            if (!(user_vocabulary.hasOwnProperty(word))) {
                user_vocabulary[word] = 1;
                ++num_added;
                if (typeof wd_user_vocab_added !== 'undefined') {
                    wd_user_vocab_added[word] = 1;
                    new_state['wd_user_vocab_added'] = wd_user_vocab_added;
                }
                if (typeof wd_user_vocab_deleted !== 'undefined') {
                    delete wd_user_vocab_deleted[word];
                    new_state['wd_user_vocab_deleted'] = wd_user_vocab_deleted;
                }
            }
        }
        if (num_added) {
            if (syncIfNeeded) {
                chrome.storage.local.set(new_state, sync_if_needed);
            } else {
                chrome.storage.local.set(new_state);
            }
        }
        var num_skipped = new_words.length - num_added;
        return {add: num_added, skip: num_skipped};
    });
}

// Required functions from common_lib.js and context_menu_lib.js

var isoLangs = {
    "ab": "Abkhaz", "aa": "Afar", "af": "Afrikaans", "ak": "Akan", "sq": "Albanian", "am": "Amharic", "ar": "Arabic", "an": "Aragonese", "hy": "Armenian", "as": "Assamese", "av": "Avaric", "ae": "Avestan", "ay": "Aymara", "az": "Azerbaijani", "bm": "Bambara", "ba": "Bashkir", "eu": "Basque", "be": "Belarusian", "bn": "Bengali", "bh": "Bihari", "bi": "Bislama", "bs": "Bosnian", "br": "Breton", "bg": "Bulgarian", "my": "Burmese", "ca": "Catalan", "ch": "Chamorro", "ce": "Chechen", "ny": "Chichewa", "zh": "Chinese", "cv": "Chuvash", "kw": "Cornish", "co": "Corsican", "cr": "Cree", "hr": "Croatian", "cs": "Czech", "da": "Danish", "dv": "Divehi", "nl": "Dutch", "en": "English", "eo": "Esperanto", "et": "Estonian", "ee": "Ewe", "fo": "Faroese", "fj": "Fijian", "fi": "Finnish", "fr": "French", "ff": "Fula", "gl": "Galician", "ka": "Georgian", "de": "German", "el": "Greek", "gn": "Guaraní", "gu": "Gujarati", "ht": "Haitian", "ha": "Hausa", "he": "Hebrew", "hz": "Herero", "hi": "Hindi", "ho": "Hiri Motu", "hu": "Hungarian", "ia": "Interlingua", "id": "Indonesian", "ie": "Interlingue", "ga": "Irish", "ig": "Igbo", "ik": "Inupiaq", "io": "Ido", "is": "Icelandic", "it": "Italian", "iu": "Inuktitut", "ja": "Japanese", "jv": "Javanese", "kl": "Kalaallisut", "kn": "Kannada", "kr": "Kanuri", "ks": "Kashmiri", "kk": "Kazakh", "km": "Khmer", "ki": "Kikuyu", "rw": "Kinyarwanda", "ky": "Kirghiz", "kv": "Komi", "kg": "Kongo", "ko": "Korean", "ku": "Kurdish", "kj": "Kwanyama", "la": "Latin", "lb": "Luxembourgish", "lg": "Luganda", "li": "Limburgish", "ln": "Lingala", "lo": "Lao", "lt": "Lithuanian", "lu": "Luba-Katanga", "lv": "Latvian", "gv": "Manx", "mk": "Macedonian", "mg": "Malagasy", "ms": "Malay", "ml": "Malayalam", "mt": "Maltese", "mi": "Māori", "mr": "Marathi", "mh": "Marshallese", "mn": "Mongolian", "na": "Nauru", "nv": "Navajo", "nb": "Norwegian Bokmål", "nd": "North Ndebele", "ne": "Nepali", "ng": "Ndonga", "nn": "Norwegian Nynorsk", "no": "Norwegian", "ii": "Nuosu", "nr": "South Ndebele", "oc": "Occitan", "oj": "Ojibwe", "cu": "Old Church Slavonic", "om": "Oromo", "or": "Oriya", "os": "Ossetian", "pa": "Panjabi", "pi": "Pāli", "fa": "Persian", "pl": "Polish", "ps": "Pashto", "pt": "Portuguese", "qu": "Quechua", "rm": "Romansh", "rn": "Kirundi", "ro": "Romanian", "ru": "Russian", "sa": "Sanskrit", "sc": "Sardinian", "sd": "Sindhi", "se": "Northern Sami", "sm": "Samoan", "sg": "Sango", "sr": "Serbian", "gd": "Scottish Gaelic", "sn": "Shona", "si": "Sinhala", "sk": "Slovak", "sl": "Slovene", "so": "Somali", "st": "Southern Sotho", "es": "Spanish", "su": "Sundanese", "sw": "Swahili", "ss": "Swati", "sv": "Swedish", "ta": "Tamil", "te": "Telugu", "tg": "Tajik", "th": "Thai", "ti": "Tigrinya", "bo": "Tibetan", "tk": "Turkmen", "tl": "Tagalog", "tn": "Tswana", "to": "Tonga", "tr": "Turkish", "ts": "Tsonga", "tt": "Tatar", "tw": "Twi", "ty": "Tahitian", "ug": "Uighur", "uk": "Ukrainian", "ur": "Urdu", "uz": "Uzbek", "ve": "Venda", "vi": "Vietnamese", "vo": "Volapük", "wa": "Walloon", "cy": "Welsh", "wo": "Wolof", "fy": "Western Frisian", "xh": "Xhosa", "yi": "Yiddish", "yo": "Yoruba", "za": "Zhuang", "zu": "Zulu"
};

function request_unhighlight(lemma) {
    chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
        chrome.tabs.sendMessage(tabs[0].id, {wdm_unhighlight: lemma});
    });
}

function sync_if_needed() {
    sync_if_needed_r2();
}

function add_lexeme(lexeme, result_handler) {
    var req_keys = ['words_discoverer_eng_dict', 'wd_idioms', 'wd_user_vocabulary', 'wd_user_vocab_added', 'wd_user_vocab_deleted'];
    chrome.storage.local.get(req_keys, function(result) {
        var dict_words = result.words_discoverer_eng_dict;
        var dict_idioms = result.wd_idioms;
        var user_vocabulary = result.wd_user_vocabulary;
        var wd_user_vocab_added = result.wd_user_vocab_added;
        var wd_user_vocab_deleted = result.wd_user_vocab_deleted;
        if (lexeme.length > 100) {
            result_handler("bad", undefined);
            return;
        }
        lexeme = lexeme.toLowerCase();
        lexeme = lexeme.trim();
        if (!lexeme) {
            result_handler("bad", undefined);
            return;
        }

        var key = lexeme;
        if (dict_words.hasOwnProperty(lexeme)) {
            var wf = dict_words[lexeme];
            if (wf) {
                key = wf[0];
            }
        } else if (dict_idioms.hasOwnProperty(lexeme)) {
            var wf = dict_idioms[lexeme];
            if (wf && wf != -1) {
                key = wf;
            }
        }

        if (user_vocabulary.hasOwnProperty(key)) {
            result_handler("exists", key);
            return;
        }

        var new_state = {'wd_user_vocabulary': user_vocabulary};

        user_vocabulary[key] = 1;
        if (typeof wd_user_vocab_added !== 'undefined') {
            wd_user_vocab_added[key] = 1;
            new_state['wd_user_vocab_added'] = wd_user_vocab_added;
        }
        if (typeof wd_user_vocab_deleted !== 'undefined') {
            delete wd_user_vocab_deleted[key];
            new_state['wd_user_vocab_deleted'] = wd_user_vocab_deleted;
        }

        chrome.storage.local.set(new_state, function() { 
            sync_if_needed();
            result_handler("ok", key);
        });
    });
}

function showDefinition(dictUrl, word) {
    var fullUrl = dictUrl + encodeURIComponent(word);
    chrome.tabs.create({'url': fullUrl}, function (tab) {
    });
}

function createDictionaryEntry(title, dictUrl, entryId) {
    chrome.contextMenus.create({"title": title, "contexts":["selection"], "id": entryId}); 
}

function context_handle_add_result(report, lemma) {
    if (report === "ok") {
        request_unhighlight(lemma);
    }
}

function onClickHandler(info, tab) {
    var word = info.selectionText;
    add_lexeme(word, context_handle_add_result);
}

function make_default_online_dicts() {
    result = [];

    var uiLang = chrome.i18n.getUILanguage();
    uiLang = uiLang.split('-')[0];
    if (uiLang != 'en' && isoLangs.hasOwnProperty(uiLang)) {
        var langName = isoLangs[uiLang];
        result.push({title: "Translate to " + langName + " in Google", url: "https://translate.google.com/#en/" + uiLang + "/"});
    }
    result.push({title: "Define in YouDao", url: "https://dict.youdao.com/result?lang=en&word="});
    result.push({title: "Define in Oxford", url: "http://localhost:8008/"});
    result.push({title: "View pictures in Google", url: "https://encrypted.google.com/search?hl=en&gl=en&tbm=isch&q="});
    return result;
}

function initContextMenus(dictPairs) {
    chrome.contextMenus.removeAll(function() {
        var title = chrome.i18n.getMessage("menuItem");
        chrome.contextMenus.create({"title": title, "contexts":["selection"], "id": "vocab_select_add"}); 
        chrome.contextMenus.create({type: 'separator', "contexts":["selection"], "id": "wd_separator_id"});
        for (var i = 0; i < dictPairs.length; ++i) {
            createDictionaryEntry(dictPairs[i].title, dictPairs[i].url, "wd_define_" + i);
        }
    });
}

// Context menu click handler
chrome.contextMenus.onClicked.addListener(function(info, tab) {
    if (info.menuItemId === "vocab_select_add") {
        var word = info.selectionText;
        add_lexeme(word, context_handle_add_result);
    } else if (info.menuItemId.startsWith("wd_define_")) {
        var word = info.selectionText;
        var index = parseInt(info.menuItemId.replace("wd_define_", ""));
        chrome.storage.local.get(['wd_online_dicts'], function(result) {
            var wd_online_dicts = result.wd_online_dicts;
            if (wd_online_dicts && wd_online_dicts[index]) {
                showDefinition(wd_online_dicts[index].url, word);
            }
        });
    }
});

// End of required functions

function initialize_extension() {
    chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
        if (request.wdm_request == "hostname") {
            tab_url = sender.tab.url;
            var url = new URL(tab_url);
            var domain = url.hostname;
            sendResponse({wdm_hostname: domain});
        } else if (request.wdm_request == "page_language") {
            chrome.tabs.detectLanguage(sender.tab.id, function(iso_language_code) {
                sendResponse({wdm_iso_language_code: iso_language_code});
            });
            return true; // This is to indicate that sendResponse would be sent asynchronously and keep the message channel open, see https://developer.chrome.com/extensions/runtime#event-onMessage
        } else if (request.wdm_verdict) {
            if (request.wdm_verdict == "highlight") {
                chrome.storage.local.get(['wd_r2_sync_enabled', 'wd_last_sync_error'], function (result) {
                    chrome.action.setIcon({path: "result48.png", tabId: sender.tab.id}, function () {
                        if (result.wd_r2_sync_enabled) {
                            if (result.wd_last_sync_error == null) {
                                chrome.action.setBadgeText({text: 'sync', tabId: sender.tab.id});
                                chrome.action.setBadgeBackgroundColor({
                                    color: [25, 137, 0, 255],
                                    tabId: sender.tab.id
                                });
                            } else {
                                chrome.action.setBadgeText({text: 'err', tabId: sender.tab.id});
                                chrome.action.setBadgeBackgroundColor({
                                    color: [137, 0, 0, 255],
                                    tabId: sender.tab.id
                                });
                            }
                        }
                    });
                });
            } else if (request.wdm_verdict == "keyboard") {
                chrome.action.setIcon({path: "no_dynamic.png", tabId: sender.tab.id});
            } else {
                chrome.action.setIcon({path: "result48_gray.png", tabId: sender.tab.id});
            }
        } else if (request.wdm_new_tab_url) {
            var fullUrl = request.wdm_new_tab_url;
            chrome.tabs.create({'url': fullUrl}, function (tab) {
            });
        } else if (request.wdm_request == "r2_sync") {
            start_sync_sequence(request.interactive_mode);
        }
    });

    chrome.storage.local.get(['words_discoverer_eng_dict', 'wd_hl_settings', 'wd_online_dicts', 'wd_hover_settings', 'wd_idioms', 'wd_show_percents', 'wd_is_enabled', 'wd_user_vocabulary', 'wd_black_list', 'wd_white_list', 'wd_r2_sync_enabled', 'wd_enable_tts'], function (result) {
        load_eng_dictionary();
        load_idioms();
        load_skip_words();
        wd_hl_settings = result.wd_hl_settings;
        if (typeof wd_hl_settings == 'undefined') {
            word_hl_params = {
                enabled: true,
                quoted: false,
                bold: true,
                useBackground: false,
                backgroundColor: "rgb(255, 248, 220)",
                useColor: true,
                color: "red"
            };
            idiom_hl_params = {
                enabled: true,
                quoted: false,
                bold: true,
                useBackground: false,
                backgroundColor: "rgb(255, 248, 220)",
                useColor: true,
                color: "blue"
            };
            wd_hl_settings = {
                wordParams: word_hl_params,
                idiomParams: idiom_hl_params,
            };
            chrome.storage.local.set({"wd_hl_settings": wd_hl_settings});
        }
        wd_enable_tts = result.wd_enable_tts;
        if (typeof wd_enable_tts == 'undefined') {
            chrome.storage.local.set({"wd_enable_tts": false});
        }
        wd_hover_settings = result.wd_hover_settings;
        if (typeof wd_hover_settings == 'undefined') {
            wd_hover_settings = {hl_hover: 'always', ow_hover: 'never'};
            chrome.storage.local.set({"wd_hover_settings": wd_hover_settings});
        }
        var wd_online_dicts = result.wd_online_dicts;
        if (typeof wd_online_dicts == 'undefined') {
            wd_online_dicts = make_default_online_dicts();
            chrome.storage.local.set({"wd_online_dicts": wd_online_dicts});
        }
        initContextMenus(wd_online_dicts);

        show_percents = result.wd_show_percents;
        if (typeof show_percents === 'undefined') {
            chrome.storage.local.set({"wd_show_percents": 15});
        }
        wd_is_enabled = result.wd_is_enabled;
        if (typeof wd_is_enabled === 'undefined') {
            chrome.storage.local.set({"wd_is_enabled": true});
        }
        user_vocabulary = result.wd_user_vocabulary;
        if (typeof user_vocabulary === 'undefined') {
            chrome.storage.local.set({"wd_user_vocabulary": {}});
        }
        black_list = result.wd_black_list;
        if (typeof black_list === 'undefined') {
            chrome.storage.local.set({"wd_black_list": {}});
        }
        white_list = result.wd_white_list;
        if (typeof white_list === 'undefined') {
            chrome.storage.local.set({"wd_white_list": {}});
        }
    });


    chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
        if (request.type = "tts_speak") {
            if (!!request.word && typeof request.word === "string") {
                chrome.tts.speak(request.word, {lang: "en", gender: "male"})
            }
        }
    });
}

initialize_extension();
